package statistics.tests;

import statistics.Asonance.IAsonance;
import statistics.Pocitani;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;

/*
*   File KruskallWallis 
*   in package statistics.tests
*   was created by slaha
*   on 2.4.12 at 18:20.
*
*/
public class KruskallWallis implements ITest{

  private ArrayList<Double> hodnoty = new ArrayList<>();
  private ArrayList<String> jmena = new ArrayList<>();
  //..HashMap<Hodnota, substituce>
  private HashMap<Double, Double> substituce = new HashMap<>();
  private ArrayList<KWData> data = new ArrayList<>();
  private double Q;
  private int N = 0;

  public KruskallWallis(ATest atest) {
    for (ATest.Mereni mereni : atest.getMereni()) {
      hodnoty.addAll(mereni.getHodnoty());
      jmena.add(mereni.getJmeno());
    }
    Collections.sort(this.hodnoty);
    this.substituce = dejHMPoradi();

    for (ATest.Mereni mereni :  atest.getMereni()) {
      data.add(new KWData(mereni.getHodnoty()));
      N += mereni.getHodnoty().size();
    }

    this.Q = dejQ();
  }

  public KruskallWallis(IAsonance asonance) {
    this(asonance.getaTest());
  }

  public double getTestovaStatistika() {
    return Q;
  }

  private double dejQ() {
    double q = 12d / ((N * (N + 1)));

    double suma = 0;

    for (KWData kwData : data) {
      double Ti2 = Math.pow(kwData.Ti, 2)/kwData.Ni;
      suma += Ti2;
    }
    q = q * suma;

    q = q - (3 * (N + 1));

    return q;
  }
  private HashMap<Double, Double> dejHMPoradi() {
    HashMap<Double, KWPomocnik> p = new HashMap<>();

    int poradoveCislo = 0;

    for(double hodnota : hodnoty) {
      ++poradoveCislo;
      if (p.containsKey(hodnota)) {
        p.get(hodnota).pocet++;
      } else {
        p.put(hodnota, new KWPomocnik(poradoveCislo));
      }
    }

    HashMap<Double, Double> ret = new HashMap<>();

    for(double d : p.keySet()) {
      ret.put(d, p.get(d).dejHodnotu());
    }

    return ret;
  }

  public ArrayList<KWData> getData() {
    return data;
  }

  public int getNi(int x) {
    return data.get(x).hodnoty.size();
  }

  public int getNvel() {
    return N;
  }

  public int getKvel() {
    return data.size();
  }

  public double getPrumer(int x) {
    return data.get(x).Ti / data.get(x).Ni;
  }
    /**
    * Data potřebná k výpočtu Kruskal-Walise
    */
  class KWData {
    ArrayList<Double> hodnoty = new ArrayList<>();
    double Ti;
    int Ni;

    KWData(ArrayList<Double> hodnoty) {
      this.hodnoty = dejHodnoty(hodnoty);
      this.Ni = hodnoty.size();
      this.Ti = dejTi();
    }

    private ArrayList<Double> dejHodnoty(ArrayList<Double> hodnoty) {
      ArrayList<Double> al = new ArrayList<>();

      for (double d : hodnoty) {
        al.add(substituce.get(d));
      }

      return al;
    }


    double dejTi() {
      double suma = 0;
      for (double d :this.hodnoty) {
        suma += d;
      }
      return suma;
    }

      public String toString() {
        String r = "";

        r += "<td><table><tr> ";
        for (double subs : hodnoty) {
          r += "<td>" + subs + "</td>";
        }
        r += "</tr></table></td>";

        r += "<td>" + Ti + "</td>";
        r += "<td>" + Ni + "</td>";

        return r;
      }
  }

  /**
   * Slouží u Kruskal-Wallisova testu k výpočtu substitučních hodnot
   */
  class KWPomocnik {

    int poradi;
    int pocet;

    KWPomocnik(int poradi) {
      this.pocet = 1;
      this.poradi = poradi;
    }

    double dejHodnotu() {
      double hodnota = poradi;
      double max = poradi + pocet - 1;
      for (int i = poradi; i < max; i++) {
        hodnota = hodnota + (i+1);
      }
      return (hodnota/pocet);
    }
  }


  @Override
  public String toString() {
    int indexJmena = 0;
    String r = "<table>";

    r += "<tr><th>Báseň</th><th>Pořadí</th><th>T<sub>i</sub></th><th>n<sub>i</sub></th></tr>";
    for (KWData d : data) {
      r += "<tr><td>" +  jmena.get(indexJmena++) + "</td>";
      r += d.toString();
      r += "</tr>";
    }
    r += "</table>";

    r += "<br><br><b>Q = " + Q + "</b>";
    try {
      double chi = new Pocitani().getChiKritickaHodnota(getKvel() - 1, 0.95);
      r += "<br>&chi;<sup>2</sup><sub>k-1</sub>(&alpha;) = &chi;<sup>2</sup><sub>"+
          getKvel() + "-1</sub>(&alpha;) = " + chi + "<br><br>";

      if (Q >= chi) {
        r += "<b>Nulová hypotéza je zamítnuta<br>" +
            "Některé básně se liší.</b>";
      } else {
        r += "<b>Nulová hypotéza je přijata<br>" +
            "Básně se od sebe výrazně neliší.</b>";
      }
    } catch (Exception ex) {
      ex.printStackTrace();
    }

    return r;
  }

  public static void main(String[] args) {
    ArrayList<Double> al1 = new ArrayList<>();
    ArrayList<Double> al2 = new ArrayList<>();
    ArrayList<Double> al3 = new ArrayList<>();
    ArrayList<Double> al4 = new ArrayList<>();
    ArrayList<Double> al5 = new ArrayList<>();
  /*  ArrayList<Double> al6 = new ArrayList<>();
    ArrayList<Double> al7 = new ArrayList<>();
    ArrayList<Double> al8 = new ArrayList<>();
    ArrayList<Double> al9 = new ArrayList<>();
    ArrayList<Double> al10 = new ArrayList<>();
    ArrayList<Double> al11 = new ArrayList<>();
    ArrayList<Double> al12 = new ArrayList<>();
    ArrayList<Double> al13 = new ArrayList<>();
    ArrayList<Double> al14 = new ArrayList<>();
    ArrayList<Double> al15 = new ArrayList<>();
    ArrayList<Double> al16 = new ArrayList<>();
*/
    al1.add(37d);
    al1.add(40d);
    al1.add(46d);

    al2.add(29d);
    al2.add(33d);
    al2.add(34d);
    al2.add(31d);

    al3.add(49d);
    al3.add(47d);

    al4.add(40d);
    al4.add(38d);
    al4.add(42d);
    al4.add(39d);
    al4.add(41d);

    al5.add(50d);
    al5.add(46d);
    al5.add(49d);
    /*
    al6.add(4d);
    al6.add(1d);
    al6.add(4d);
    al6.add(7d);
    al6.add(4d);
    al6.add(16d);

    al7.add(1d);
    al7.add(7d);
    al7.add(1d);
    al7.add(7d);
    al7.add(6d);
    al7.add(7d);

    al8.add(3d);
    al8.add(3d);
    al8.add(8d);
    al8.add(4d);
    al8.add(8d);
    al8.add(10d);

    al9.add(3d);
    al9.add(1d);
    al9.add(1d);
    al9.add(1d);
    al9.add(9d);
    al9.add(1d);

    al10.add(3d);
    al10.add(14d);
    al10.add(14d);
    al10.add(1d);
    al10.add(1d);

    al11.add(3d);
    al11.add(14d);
    al11.add(2d);
    al11.add(3d);
    al11.add(14d);
    al11.add(10d);

    al12.add(4d);
    al12.add(12d);
    al12.add(3d);
    al12.add(12d);
    al12.add(14d);
    al12.add(1d);

    al13.add(3d);
    al13.add(14d);
    al13.add(1d);
    al13.add(14d);
    al13.add(1d);
    al13.add(14d);

    al14.add(8d);
    al14.add(14d);
    al14.add(6d);
    al14.add(4d);
    al14.add(14d);
    al14.add(14d);

    al15.add(4d);
    al15.add(1d);
    al15.add(4d);
    al15.add(14d);
    al15.add(4d);
    al15.add(4d);
    al15.add(4d);

    al16.add(14d);
    al16.add(10d);
*/
    ATest atest = new ATest();
    atest.add(al1);
    atest.add(al2);
    atest.add(al3);
    atest.add(al4);
    atest.add(al5);
 /*   atest.add(al6);
    atest.add(al7);
    atest.add(al8);
    atest.add(al9);
    atest.add(al10);
    atest.add(al11);
    atest.add(al12);
    atest.add(al13);
    atest.add(al14);
    atest.add(al15);
    atest.add(al16);*/

    KruskallWallis kw = new KruskallWallis(atest);
    try {
      boolean Ha = kw.getTestovaStatistika() >= new Pocitani().getChiKritickaHodnota(kw.getKvel() - 1, 0.95);
      if (Ha) {
        Scheffe scheffe = new Scheffe(kw);
      }
    } catch (Exception e) {
      e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
    }
  }
}
